/*
 *  $Id: Flag.cs 975 2009-12-16 17:13:22Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;

namespace Ragima {
    /// <summary>
    /// Абстрактный эффект-флаг, влияющий на что-либо лишь своим наличием или отсутствием.
    /// </summary>
    public abstract class FlagAffect: Affect {
        public override void SetAffect() {
            base.SetAffect();
            LocalSummary.Flags.SetFlag(GetType());
        }
        public override void ResetAffect() {
            base.ResetAffect();
            LocalSummary.Flags.ResetFlag(GetType());
        }
    }

    /// <summary>
    /// Счетчик флагов и анти-флагов.
    /// </summary>
    public sealed class FlagAffectCounter {
        private uint _counter, _counterAnti;

        public FlagAffectCounter() {
            _counter = 0;
            _counterAnti = 0;
        }

        public bool Active {
            get { return _counter > 0 && _counterAnti == 0; }
        }
        public bool Empty {
            get { return _counter == 0 && _counterAnti == 0; }
        }

        public void SetFlag() {
            _counter++;
        }
        public void ResetFlag() {
            _counter--;
        }
        public void SetAntiFlag() {
            _counterAnti++;
        }
        public void ResetAntiFlag() {
            _counterAnti--;
        }
    }

    public sealed class FlagDictionary {
        private Dictionary<Type, FlagAffectCounter> _flags;

        public FlagDictionary() {
            _flags = new Dictionary<Type,FlagAffectCounter>();
        }

        public bool this[Type key] {
            get { return HasFlag(key); }
        }

        public bool HasFlag(Type key) {
            FlagAffectCounter counter;
            if (_flags.TryGetValue(key, out counter))
                return counter.Active;
            else
                return false;
        }

        private FlagAffectCounter GetCounter(Type key) {
            FlagAffectCounter counter;
            if (!_flags.TryGetValue(key, out counter)) {
                counter = new FlagAffectCounter();
                _flags.Add(key, counter);
            }
            return counter;
        }

        public void SetFlag(Type key) {
            FlagAffectCounter counter = GetCounter(key);
            counter.SetFlag();
        }
        public void ResetFlag(Type key) {
            FlagAffectCounter counter = GetCounter(key);
            counter.ResetFlag();
            if (counter.Empty) _flags.Remove(key);
        }
        public void SetAntiFlag(Type key) {
            FlagAffectCounter counter = GetCounter(key);
            counter.SetAntiFlag();
        }
        public void ResetAntiFlag(Type key) {
            FlagAffectCounter counter = GetCounter(key);
            counter.ResetAntiFlag();
            if (counter.Empty) _flags.Remove(key);
        }
    }
}

namespace Ragima.Affects {
    /// <summary>
    /// Эффект: анти-флаг
    /// Запрещает действие определенного флага.
    /// </summary>
    public class AntiFlag: Affect {
        public readonly Type FlagType;

        public AntiFlag(Type flag) {
            FlagType = flag;
        }

        public override string Id {
            get { return "antiflag"; }
        }

        public override string NameText {
            get { return Name.GetText(FlagType.Name); }
        }

        // TODO: получение веса основного эффекта
        public override int BaseWeight {
            get { return 0; }
        }

        public override Affect Clone() {
            return new AntiFlag(FlagType);
        }

        public override void SetAffect() {
            base.SetAffect();
            LocalSummary.Flags.SetAntiFlag(FlagType);
        }
        public override void ResetAffect() {
            base.ResetAffect();
            LocalSummary.Flags.ResetAntiFlag(FlagType);
        }
    }

    /// <summary>
    /// Эффект: анти-флаг (генерик-версия)
    /// Запрещает действие определенного флага.
    /// </summary>
    public class AntiFlag<T>: AntiFlag where T: FlagAffect {
        public AntiFlag(): base(typeof(T)) {}

        public override Affect Clone() {
            return new AntiFlag<T>();
        }
    }
}
